package com.abc.tomcat;

import com.abc.servnet.Servnet;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpServerCodec;

import java.io.File;
import java.net.URL;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Tomcat 服务器核心
 */
public class TomcatServer {

    //Key 为 Servnet 的名称 是该Servnet 类的简单类名全小写，value为该Servnet类的全限性类名
    private Map<String, String> classNameMap = new ConcurrentHashMap<>();
    //Key 为 Servnet 的名称 是该Servnet 类的简单类名全小写，value为该Servnet 实例
    private Map<String, Servnet> instanceMap = new ConcurrentHashMap<>();

    //默认扫描包名
    private String basePackage;

    public TomcatServer(String basePackage) {
        this.basePackage = basePackage;
    }

    public void start() throws Exception {
        //加载制定包中的类名
        cacheClassName(basePackage);

        //运行tomcat
        runServer();

    }

    //调用netty 启动一个服务
    private void runServer() {
        NioEventLoopGroup parentGroup = new NioEventLoopGroup();

        NioEventLoopGroup childGroup = new NioEventLoopGroup();
        try{
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(parentGroup, childGroup)
                    //制定存放已连接上但是还来不及处理的请求队列长度
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    //为了保证长连接不被清除掉
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {

                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline  = ch.pipeline();
                            pipeline.addLast(new HttpServerCodec());
                            pipeline.addLast(new TomcatServerHandler(classNameMap, instanceMap));
                        }
                    });
            ChannelFuture future = bootstrap.bind(8888).sync();
            System.out.println("启动");
            future.channel().closeFuture().sync();
        }catch (Exception e){

        }finally {
            parentGroup.shutdownGracefully();
            childGroup.shutdownGracefully();
        }

    }

    private void cacheClassName(String basePackage) {
        //加载制定的包为URL   com.abc.webapp  => com/abc/webapp
        URL resource = this.getClass().getClassLoader().getResource(basePackage.replaceAll("\\.", "/"));

        if (resource == null) {
            return;
        }

        //将URL资源转换为 File
        File dir = new File(resource.getFile());
        System.out.println(dir);
        //遍历指定包及其子孙包中所欲的文件，查找 .class 文件
        for (File file : dir.listFiles()) {
            if (file.isDirectory()) {
                //目录递归
                cacheClassName(basePackage + "." + file.getName());
            } else if (file.getName().endsWith(".class")) {
                //去掉 .class 扩展名 ,获取到简单类名
                String fileName = file.getName().replace(".class", "");
                classNameMap.put(fileName.toLowerCase(), basePackage + "." +fileName );
            }
        }
    }


}
